#include <stdio.h>
#include <errno.h>
#include <sys/epoll.h>
#include <stdlib.h>
#include "reactor.h"
#include "event.h"
#include "acceptor.h"

reactor_t *create_reactor(int epollfd,thpool_t *thpool){
	reactor_t *reactor;

	reactor = (reactor_t *)malloc(sizeof(reactor_t));
	if(reactor == NULL){
		outputError(errno,"%s","malloc reactor");
	}

	reactor->add_eh = add_event_handle;
	reactor->rm_eh = rm_event_handle;
	reactor->event_loop = event_loop;
	reactor->thpool = thpool;
	reactor->acceptor = NULL;
	
	reactor->core = (reactor_core_t *)malloc(sizeof(reactor_core_t));
	if(reactor->core == NULL){
		outputError(errno,"%s","malloc reactor_core");
	}

	reactor->core->epoll_fd = epollfd;
	reactor->core->eh_list = (event_handler_list_t *)malloc(sizeof(event_handler_list_t));
	if(reactor->core->eh_list == NULL){
		outputError(errno,"%s","malloc event_handler_list_t");
	}

	reactor->core->eh_list->current_len = 0;
	reactor->core->eh_list->head = reactor->core->eh_list->tail = NULL;

	return reactor;
}

int add_event_handle(struct reactor *self,event_handler_t *eh){
	struct epoll_event ev;
	event_handler_node_t *node;

	if(self->core->eh_list->current_len >= MAX_USERS){
		outputError(errno,"%s%d","limit ",MAX_USERS);
	}else{
		node = (event_handler_node_t *)malloc(sizeof(event_handler_node_t));
		if(node == NULL){
			outputError(errno,"%s","malloc event_handler_node_t");
		}
		node->eh = eh;
		node->next = NULL;
		if(self->core->eh_list->current_len == 0){
			self->core->eh_list->head = self->core->eh_list->tail = node;
		}else{
			self->core->eh_list->tail->next = node;
			self->core->eh_list->tail = node;
		}
		self->core->eh_list->current_len++;
	}

	ev.data.fd = eh->fd;
	ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
	//ev.events = EPOLLIN;

	if(epoll_ctl(self->core->epoll_fd,EPOLL_CTL_ADD,eh->fd,&ev) != 0){
		outputError(errno,"%s","epoll_ctl");
	}

	return 0;
}

int rm_event_handle(struct reactor *self,int fd){
	int i;
	event_handler_node_t *node,*prev;

	for(i = 1,node = self->core->eh_list->head,prev = NULL; i <= self->core->eh_list->current_len; i++,prev = node,node = node->next){
		if(node->eh->fd == fd){
			break;
		}
	}

	if(i > self->core->eh_list->current_len){
		outputError(errno,"%s","could not find eh");
	}

	if(--self->core->eh_list->current_len == 0){
		self->core->eh_list->head = self->core->eh_list->tail = NULL;
	}else{
		prev->next = node->next;
		self->core->eh_list->tail = prev;
	}

	free(node->eh);
	free(node);

	if(epoll_ctl(self->core->epoll_fd,EPOLL_CTL_DEL,fd,NULL) == -1){
		outputError(errno,"%s","epoll_ctl");
	}
}

int event_loop(struct reactor *self){
	struct epoll_event evlist[MAX_USERS];
	int readyN,i;
	event_handler_t *eh;
	handle_event_msg_t arg;

	while(1){
		if((readyN = epoll_wait(self->core->epoll_fd,evlist,MAX_USERS,-1)) == -1){
			if(errno == EINTR){
				continue;
			}else{
				outputError(errno,"%s","epoll_wait");
			}
		}

		printf("readyn = %d\n",readyN);

		for(i = 0; i < readyN; i++){

			if(evlist[i].events & EPOLLIN){
				if(evlist[i].data.fd == self->acceptor->listenfd){
					self->acceptor->handle_event(self);
				}else{
					eh = find_eh(self,evlist[i].data.fd);
					arg.eh = eh;
					arg.events = evlist[i].events;
					arg.fd = evlist[i].data.fd;

					insert_jobqueue(self->thpool,eh,arg);
				}
			}

			if(evlist[i].events & (EPOLLHUP | EPOLLERR | EPOLLRDHUP)){
				rm_event_handle(self,evlist[i].data.fd);
				printf("user down and eh num %d\n",self->core->eh_list->current_len);
			}

		}
	}
}

event_handler_t *find_eh(struct reactor *self,int fd){
	int i;
	event_handler_node_t *node;

	for(i = 1,node = self->core->eh_list->head; i <= self->core->eh_list->current_len; i++,node = node->next){
		if(node->eh->fd == fd){
			break;
		}
	}

	if(i > self->core->eh_list->current_len){
		outputError(errno,"%s","could not find eh");
	}

	return node->eh;
}
